package request

import (
	"bytes"
	"compress/gzip"
	"crypto/tls"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"strings"
)

func HttpGet(uri string, params url.Values) ([]byte, error) {
	if len(map[string][]string(params)) > 0 {
		if strings.Index(uri, "?") > -1 {
			uri = uri + "&" + params.Encode()
		} else {
			uri = uri + "?" + params.Encode()
		}
	}
	log.Println("HttpGetAsObj " + uri)
	if req, err := http.NewRequest("GET", uri, nil); err != nil {
		return nil, err
	} else {
		return sendRequest(req)
	}
}

func HttpGetAsObj(uri string, params url.Values, obj interface{}) error {
	bs, err := HttpGet(uri, params)
	log.Println(string(bs))
	if err != nil {
		return err
	}
	return json.Unmarshal(bs, obj)
}

func HttpPost(uri string, params url.Values) ([]byte, error) {
	log.Println("HttpPostAsObj " + uri + "\n" + params.Encode())
	if req, err := http.NewRequest("POST", uri, strings.NewReader(params.Encode())); err != nil {
		return nil, err
	} else {
		return sendRequest(req)
	}
}

func HttpPostAsObj(uri string, params url.Values, obj interface{}) error {
	bs, err := HttpPost(uri, params)
	log.Println(string(bs))
	if err != nil {
		return err
	}
	return json.Unmarshal(bs, obj)
}

// Creates a new file upload http request with optional extra params
func HttpMultipart(uri string, params url.Values, fieldname, filename string, file io.Reader) ([]byte, error) {
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(fieldname, filename)
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(part, file)
	if err != nil {
		return nil, err
	}

	for key, val := range params {
		for _, i_val := range val {
			if err = writer.WriteField(key, i_val); err != nil {
				return nil, err
			}
		}
	}
	err = writer.Close()
	if err != nil {
		return nil, err
	}

	log.Println("HttpMultipartAsObj " + uri + "\n" + params.Encode())
	if req, err := http.NewRequest("POST", uri, body); err != nil {
		return nil, err
	} else {
		req.Header.Add("Content-Type", "multipart/form-data; boundary="+writer.Boundary())
		return sendRequest(req)
	}
}

func HttpMultipartAsObj(uri string, params url.Values, fieldname, filename string, file io.Reader, obj interface{}) error {
	bs, err := HttpMultipart(uri, params, fieldname, filename, file)
	log.Println(string(bs))
	if err != nil {
		return err
	}
	return json.Unmarshal(bs, obj)
}

func sendRequest(request *http.Request) ([]byte, error) {
	request.Header.Add("Accept-Encoding", "gzip, deflate, sdch")
	client := &http.Client{}
	if request.URL.Scheme == "https" {
		client.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	}
	resp, err := client.Do(request)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	if resp.StatusCode == 200 {
		if "gzip" == resp.Header.Get("Content-Encoding") {
			if reader, err := gzip.NewReader(resp.Body); err == nil {
				defer reader.Close()
				return ioutil.ReadAll(reader)
			}
		}
		return ioutil.ReadAll(resp.Body)
	}
	bs, _ := ioutil.ReadAll(resp.Body)
	return bs, errors.New(resp.Status)
}
